package com.yuneec.droneservice;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.util.SparseArray;

import com.yuneec.droneservice.connection.AOAConnection;
import com.yuneec.droneservice.protocol.ProtocolPlugin;
import com.yuneec.droneservice.protocol.analysis.CameraStreamReceiver;
import com.yuneec.droneservice.protocol.analysis.IMessageReceiver;
import com.yuneec.droneservice.protocol.analysis.MediaStreamReceiver;
import com.yuneec.droneservice.request.DispatchService;
import com.yuneec.droneservice.request.IRequest;
import com.yuneec.droneservice.request.OnListener;
import com.yuneec.droneservice.request.OnRequestListener;
import com.yuneec.droneservice.tools.RCLog;

import java.util.LinkedList;
import java.util.List;

/**
 * Created by lk.sun on 3/8/2016. Provide interface for communication with Drone
 * and Controller.
 */
public class DroneService extends Service {
    private final DroneBinder mBinder = new DroneBinder();
    private SparseArray<List<OnListener<?>>> listeners;
    private List<ConnectionListener> mConnectionListenerList;
    private ConnectionListener mConnectionListener;
    private DispatchService dispatchService;
    private AOAConnection mConnectionInterface;
    private Handler doBackgroundHandler;
    private boolean isConnected = false;

    private void initListener() {
        listeners = new SparseArray<>(10);
        listeners.put(OnListener.L_CONTROLLER_FEEDBACK, new LinkedList<OnListener<?>>());
        listeners.put(OnListener.L_DRONE_FEEDBACK, new LinkedList<OnListener<?>>());
        listeners.put(OnListener.L_PAYLOAD_BY_PASS, new LinkedList<OnListener<?>>());
        mConnectionListenerList = new LinkedList<>();

        mConnectionListener = new ConnectionListener() {

            @Override
            public void onConnected() {
                RCLog.d("onConnected");
                isConnected = true;
                for (final ConnectionListener l : mConnectionListenerList) {
                    l.onConnected();
                }
            }

            @Override
            public void onDisconnected() {
                for (final ConnectionListener l : mConnectionListenerList) {
                    l.onDisconnected();
                }
                isConnected = false;
                RCLog.d("onDisconnected");
            }
        };
    }

    @Override
    public void onCreate() {
        super.onCreate();
        initListener();
        HandlerThread handlerThread = new HandlerThread("service-background-thread");
        handlerThread.start();
        doBackgroundHandler = new Handler(handlerThread.getLooper());
        mConnectionInterface = new AOAConnection(this);
        ProtocolPlugin plugin = ServiceManager.getInstance().getProtocolPlugin();
        plugin.init(mBinder);
        dispatchService = new DispatchService(mConnectionInterface, plugin);
        dispatchService.start();
        mConnectionInterface.setReceiveListener(dispatchService);
    }

    public void init(Context context) {
        mConnectionInterface.open(null, mConnectionListener);
    }

    public void deinit(Context context) {
        mConnectionInterface.close();
    }

    @Override
    public void onDestroy() {
        dispatchService.stop();
        dispatchService = null;
        //////////////////////////////////////////////////////
        doBackgroundHandler.removeCallbacksAndMessages(null);
        doBackgroundHandler.getLooper().quit();
        for (int i = 0; i < listeners.size(); i++) {
            listeners.valueAt(i).clear();
        }
        listeners.clear();
        mConnectionListenerList.clear();
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    public class DroneBinder extends Binder {

        public void init(Context context) {
            DroneService.this.init(context);
        }

        public void deinit(Context context) {
            DroneService.this.deinit(context);
        }

        public void asyncSendCommand(final IRequest request, final OnRequestListener listener) {
            doBackgroundHandler.post(new Runnable() {
                @Override
                public void run() {
                    dispatchService.sendCommand(request, listener);
                }
            });
        }

        public final void clearListener(int id) {
            List<OnListener<?>> list = listeners.get(id);
            if (list != null) {
                list.clear();
            }
        }

        public final void registerListener(int id, OnListener<?> listener) {
            if (listener == null) {
                return;
            }
            List<OnListener<?>> list = listeners.get(id);
            if(list==null){
                list=new LinkedList<>();
                listeners.put(id,list);
            }
            list.add(listener);
        }

        public final void unregisterListener(int id, OnListener<?> listener) {
            if (listener == null) {
                return;
            }
            List<OnListener<?>> list = listeners.get(id);
            if (list != null) {
                list.remove(listener);
            }
        }

        public boolean isConnected() {
            return isConnected;
        }

        public void clearConnectionListener() {
            mConnectionListenerList.clear();
        }

        public void registerConnectionListener(ConnectionListener listener) {
            if (listener == null) {
                return;
            }
            if (isConnected) {
                listener.onConnected();
            } else {
                listener.onDisconnected();
            }
            mConnectionListenerList.add(listener);
        }

        public void unregisterConnectionListener(ConnectionListener listener) {
            if (listener == null) {
                return;
            }
            mConnectionListenerList.remove(listener);
        }

        public void setMediaStreamReceiver(MediaStreamReceiver receiver) {
            if (mConnectionInterface != null) {
                if (receiver != null) {
                    mConnectionInterface.registReceiver(receiver);
                } else {
                    mConnectionInterface.unRegistReceiver(MediaStreamReceiver.MEDIA_ID);
                }
            }
        }

        public void setCameraStreamReceiver(CameraStreamReceiver receiver) {
            if (mConnectionInterface != null) {
                if (receiver != null) {
                    mConnectionInterface.registReceiver(receiver);
                } else {
                    mConnectionInterface.unRegistReceiver(CameraStreamReceiver.CAMERA_ID);
                }
            }
        }

        public void registStreamReceive(IMessageReceiver receiver) {
            if (mConnectionInterface != null) {
                if (receiver != null) {
                    mConnectionInterface.registReceiver(receiver);
                }
            }
        }

        public void unregistStreamReceive(IMessageReceiver receiver) {
            if (mConnectionInterface != null) {
                if (receiver != null) {
                    mConnectionInterface.unRegistReceiver(receiver.getMessageId());
                }
            }
        }

        public void unregistStreamReceive(int portId) {
            if (mConnectionInterface != null) {
                mConnectionInterface.unRegistReceiver(portId);
            }
        }

        public void reInit(Context context) {
        }

        public int writeAOADataBlock(int id, byte[] buf) {
            if (mConnectionInterface != null) {
                return mConnectionInterface.writeDataBlock(id, buf);
            }
            return -1;
        }

        public void writeAOAData(int id, byte[] buf) {
            if (mConnectionInterface != null) {
                mConnectionInterface.writeData(id, buf);
            }
        }

        public void sendMessage(int msgId, Object arg) {
            doBackgroundHandler.sendMessage(doBackgroundHandler.obtainMessage(msgId, arg));
        }

        public List<OnListener<?>> getListener(int id) {
            return listeners.get(id);
        }
    }
}
